package gui;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;

import javax.swing.JPanel;

import AI.Literal;
import AI.LiteralType;

import world.FieldValues;
import world.Map;

/**
 * @author Maciej Skrzypkowski
 * 
 * Main panel which shows game field and current game state.
 *
 */
public class GamePanel extends JPanel {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
    private GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    private GraphicsConfiguration graphicsConfiguration = ge.getDefaultScreenDevice().getDefaultConfiguration();
    private Image dbImage = null;
    private Graphics graphics;
    
    private static final String FONT = "DejaVu Sans Mono"; 
    private static final int TEXT_SCALE = 40;
    private static final int SMALL_TEXT = 21;
	private Font font = new Font(FONT, Font.BOLD, TEXT_SCALE);
	private Font smallFont = new Font(FONT, Font.BOLD, SMALL_TEXT);
	
	private MainFrame mainFrame;
	

    public GamePanel(MainFrame mainFrame) {
		super();
		setBackground(new Color(255,255,255));
		this.mainFrame = mainFrame;
		
		// if window is resized create image of new window size
		addComponentListener(new ComponentAdapter() {
			public void componentResized(ComponentEvent e) {
				dbImage = graphicsConfiguration.createCompatibleImage(getWidth(), getHeight());
				if (dbImage == null) {
					System.out.println("dbImage is null");
					return;
				} else
					graphics = dbImage.getGraphics();
			}
		});
	}

    
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
    }

    
    public void paint(Graphics g) {
    	super.paint(g);
    	paintObjects(g);
    }

    
	public void update() {
		if (dbImage == null) {
			dbImage = graphicsConfiguration.createCompatibleImage(getWidth(), getHeight());
			if (dbImage == null) {
				System.out.println("dbImage is null");
				return;
			} else
				graphics = dbImage.getGraphics();
		}
				      
        paint(graphics);
        
        drawOnScreenFromBuffer(this.getGraphics());		
	}
	
	
    private void drawOnScreenFromBuffer(Graphics g) {
        try {
          if ((g != null) && (dbImage != null))
            g.drawImage(dbImage, 0, 0, null);
          Toolkit.getDefaultToolkit().sync();  // sync the display on some systems
          g.dispose();
        }
        catch (Exception e) { 
            System.out.println("Graphics error: " + e);  
        }
    }
    
    /**
     * Paints all objects described in physics model.
     */
    private void paintObjects(Graphics g) {	
    	// draw background
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, getWidth(), getHeight());
        
        // draw net
        g.setColor(Color.BLACK);
        int xStep = getWidth() / mainFrame.getFieldSize();
        int yStep = getHeight() / mainFrame.getFieldSize();  
        for(int i=0; i<mainFrame.getFieldSize(); ++i) {
        	g.drawLine(i*xStep, 0, i*xStep, getHeight());
        }    
        for(int i=0; i<mainFrame.getFieldSize(); ++i) {
        	g.drawLine(0, i*yStep, getWidth(), i*yStep);
        }        
        
        // draw game objects:
        int textSize = TEXT_SCALE * MainFrame.DEF_FIELD_SIZE / mainFrame.getFieldSize();
        int textSizeSmall = SMALL_TEXT * MainFrame.DEF_FIELD_SIZE / mainFrame.getFieldSize();
        if (textSize > 100)
        	textSize = 100;
        if (textSizeSmall > 70)
        	textSizeSmall = 70;
        font = new Font(FONT, Font.BOLD, textSize);
        smallFont = new Font(FONT, Font.BOLD, textSizeSmall);
        Graphics2D g2 = (Graphics2D) g;
    	FontRenderContext frc = g2.getFontRenderContext();
    	
    	try {
    		Map map = Main.getInstance().getMap();
	    	if (map != null) {
	    		int grid[][] = map.getGrid();
	    		int size = map.getSize();
	    		for (int i=0; i<size; ++i) {
	    			for (int j=0; j<size; ++j) {
	    				paintObject(grid[j][i], new Point(i,j), frc, g2, xStep, yStep);
	    			}
	    		}
	    	} else {
	    		System.out.println("GamePanel.paintObjects: There is no map!");
	    	}
    	} catch (Exception e) {
    		System.out.println(e);
			e.printStackTrace();
		}
    	
    }
    
    
    private void paintObject(int fieldType, Point position, FontRenderContext frc, Graphics2D g2, int xStep, int yStep) throws NoSuchFieldException {
    	String s = null;
    	int corner = 0;	// remembers field corner, when there are few signals in one field
    	boolean doNotShow = false;
    	
    	
    	do {
        	int currentField = 0;
        	if (fieldType % FieldValues.WUMPUS.getNumber() == 0) {
        		g2.setColor(Color.BLACK);
        		s = "W";
        		currentField = FieldValues.WUMPUS.getNumber();
          	} else if (fieldType % FieldValues.BREEZE.getNumber() == 0) { 
        		g2.setColor(Color.BLUE);
        		s = "B";
        		currentField = FieldValues.BREEZE.getNumber();
        	} else if (fieldType == FieldValues.EMPTY.getNumber()) {
        		s = null;
        		currentField = FieldValues.EMPTY.getNumber();
        	} else if (fieldType % FieldValues.GOLD.getNumber() == 0) {
//        		g2.setColor(Color.YELLOW);
//        		s = "G";
        		doNotShow = true;
        		currentField = FieldValues.GOLD.getNumber();
        	} else if (fieldType % FieldValues.PIT.getNumber() == 0) {
        		g2.setColor(Color.GREEN);
        		s = "P";
        		currentField = FieldValues.PIT.getNumber();
        	} else if (fieldType % FieldValues.STENCH.getNumber() == 0) {
        		g2.setColor(Color.CYAN);
        		s = "S";
        		currentField = FieldValues.STENCH.getNumber();
        	} else if (fieldType % FieldValues.GLITTER.getNumber() == 0) {
        		g2.setColor(Color.ORANGE);
        		s = "G";
        		currentField = FieldValues.GLITTER.getNumber();
        	} else if (fieldType % (FieldValues.UP.getNumber() * FieldValues.AGENT.getNumber()) == 0) {
        		g2.setColor(Color.RED);
	    		s = "↑";
	    		currentField = FieldValues.UP.getNumber() * FieldValues.AGENT.getNumber();
        	} else if (fieldType % (FieldValues.DOWN.getNumber() * FieldValues.AGENT.getNumber())== 0) {
        		g2.setColor(Color.RED);
				s = "↓";
	    		currentField = FieldValues.DOWN.getNumber() * FieldValues.AGENT.getNumber();
        	}  else if (fieldType % (FieldValues.RIGHT.getNumber() * FieldValues.AGENT.getNumber()) == 0) {
        		g2.setColor(Color.RED);
        		s = "→";
	    		currentField = FieldValues.RIGHT.getNumber() * FieldValues.AGENT.getNumber();
        	}  else if (fieldType % (FieldValues.LEFT.getNumber() * FieldValues.AGENT.getNumber()) == 0) {
        		g2.setColor(Color.RED);
        		s = "←";
	    		currentField = FieldValues.LEFT.getNumber() * FieldValues.AGENT.getNumber();
        	} else
        	{
        		throw new NoSuchFieldException();
        	} 
        	
        	fieldType /= currentField;
        	
        	if (doNotShow) {
        		doNotShow = false;
        		continue;
        	}
        		
        	
        	if (fieldType > 1 || corner > 0) {	// if there are more signals in this field
        		++corner;
        	}

	    	if (s != null) {
	        	switch (corner) {
				case 0:
			    	TextLayout tl = new TextLayout(s, font, frc);
			    	tl.draw(g2, xStep*position.x + (int)(0.3*xStep), yStep*position.y + (int)(0.9*yStep));
					break;
				case 1:
			    	tl = new TextLayout(s, smallFont, frc);
			    	tl.draw(g2, xStep*position.x + (int)(0.1*xStep), yStep*position.y +(int)(0.4*yStep));
			    	break;
				case 2:
			    	tl = new TextLayout(s, smallFont, frc);
			    	tl.draw(g2, xStep*position.x + (int)(0.5*xStep), yStep*position.y +(int)(0.4*yStep));
					break;
				case 3:
			    	tl = new TextLayout(s, smallFont, frc);
			    	tl.draw(g2, xStep*position.x + (int)(0.1*xStep), yStep*position.y +(int)(0.9*yStep));
					break;
				case 4:
			    	tl = new TextLayout(s, smallFont, frc);
			    	tl.draw(g2, xStep*position.x + (int)(0.5*xStep), yStep*position.y +(int)(0.9*yStep));
					break;
				default:
					System.out.println("paintObject: Corner value too high!");
					break;
				}
	    	}
    	} while (fieldType > 1);
    	
//    	// draw agent
//    	if (fieldType == LiteralType.AGENT.getNumber()) {
//    		g2.setColor(Color.RED);
//    		switch (Main.getInstance().getPlayerPos()) {
//			case UP:
//	    		s = "↑";
//				break;
//			case DOWN:
//				s = "↓";
//				break;
//			case RIGHT:
//				s = "→";
//				break;
//			case LEFT:
//				s = "←";
//				break;
//			default:
//				break;
//			}
//    		
//	    	TextLayout tl = new TextLayout(s, font, frc);
//	    	tl.draw(g2, xStep*position.x + (int)(0.3*xStep), yStep*position.y + (int)(0.9*yStep));
//    	}
    }
   
}
